﻿using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Linq;
using Microsoft.SqlServer.Types;
using MyFloridaHouse.DataAccess;
using MyFloridaHouse.libSTO;
using MyFloridaHouse.libSvCommonUtilities;
using MyFloridaHouse.libSvDTO;

namespace MyFloridaHouse.libServiceBusinessRules
{
	/// <summary>
	/// District Shape
	/// </summary>
    public static class DistrictShape
    {
        public static DistrictShapeSTO GetDistrictShape(byte[] compressedShapeList, int districtID)
        {
            DistrictShapeSTO result = new DistrictShapeSTO();
            result.districtID = districtID;
            if (districtID != 0)
            {
                try
                {
                    SqlGeometry geom = null;
                    string shapeList = CompressionManager.Decompress(compressedShapeList); //this is the regionID list
                    if (shapeList.Length > 0)
                    {
                        DAL_CensusData dal = new DAL_CensusData();
                        geom = DistrictShapeBuilder.BuildDistrict(dal.GetDistrictGeometryShape(shapeList));
                    }
                    else
                    {
                        // build the default shape
                        geom = SQLGeometryTools.BuildDefaultDistrictShape();
                    }
                    result.centerPoint = SQLGeometryTools.GetLabelLocation(geom);
                    result.districtShapeBoundingBox = BoundingBoxHelpers.GeometrySTEnvelopeToBox(geom.MakeValid().STEnvelope());
                    result.districtSubShapeList = GetDistrictSubshapes(geom);
                    result.districtHolesList = GetDistrictHoles(geom);
                    result.mapMultiShapeDTO = SQLGeometryTools.ToMapMultiShapeDTO(geom);

                }
                catch (Exception ex)
                {
                    result.errorMessage = "CensusDataService: Get District Shape failed for District [" + districtID.ToString() + "] " + ex.Message;
                }
            }
            return result;
        }

        private static List<BoundingBoxDTO> GetDistrictSubshapes(SqlGeometry geom)
        {
            List<SubShapesWithArea> districtSubShapeListWithArea = new List<SubShapesWithArea>();
            List<BoundingBoxDTO> districtSubShapeList = new List<BoundingBoxDTO>();
            SqlGeometry currentGeom;
            SqlInt32 numGeographies = geom.STNumGeometries();
            for (int ndx = 1; ndx <= numGeographies; ndx++)
            {
                SqlGeometry currentGeog = geom.STGeometryN(ndx);
                //if (((string)currentGeog.STGeometryType() == "Polygon") && (currentGeog.STArea() > 1))
                if ((string)currentGeog.STGeometryType() == "Polygon")
                {
                    //Todo: create a const for the Bing Map units
                    currentGeom = SqlGeometry.STGeomFromText(currentGeog.STAsText(), 4326).MakeValid();
                    SubShapesWithArea subShape = new SubShapesWithArea();
                    subShape.area = (double)currentGeog.STArea();
                    //Spatial STEnvelope function returns a bounding box with a list of 5 points, 1 = southeast, 3 = northwest
                    subShape.boundingBox = BoundingBoxHelpers.GeometrySTEnvelopeToBox(currentGeog.MakeValid().STEnvelope());
                    districtSubShapeListWithArea.Add(subShape);
                }
            }
            districtSubShapeListWithArea.Sort((x, y) => (x.area.CompareTo(y.area)));
            districtSubShapeList = (from s in districtSubShapeListWithArea
                                    select s.boundingBox).ToList();
            return districtSubShapeList;
        }

        private static List<BoundingBoxDTO> GetDistrictHoles(SqlGeometry geom)
        {
            List<SubShapesWithArea> districtHoleListWithArea = new List<SubShapesWithArea>();
            List<BoundingBoxDTO> districtHoleList = new List<BoundingBoxDTO>();

            int numGeometries = (int)geom.STNumGeometries();
            SqlInt32 interiorRingCount = 0;
            SqlGeometry interiorRingGeom;
            for (int ndx = 1; ndx <= numGeometries; ndx++)
            {
                SqlGeometry currentGeom = geom.STGeometryN(ndx);
                if ((string)currentGeom.STGeometryType() == "Polygon")
                {
                    interiorRingCount = currentGeom.STNumInteriorRing();
                    for (int i = 1; i <= interiorRingCount; i++)
                    {
                        interiorRingGeom = currentGeom.STInteriorRingN(i);
                        SubShapesWithArea subShapeInterioRing = new SubShapesWithArea();
                        //Spatial STEnvelope function returns a bounding box with a list of 5 points, 1 = southeast, 3 = northwest
                        subShapeInterioRing.boundingBox = BoundingBoxHelpers.GeometrySTEnvelopeToBox(interiorRingGeom.MakeValid().STEnvelope());
                        subShapeInterioRing.area = BoundingBoxHelpers.AreaFromBoundingBox(subShapeInterioRing.boundingBox);
                        districtHoleListWithArea.Add(subShapeInterioRing);
                    }
                }

            }

            districtHoleListWithArea.Sort((x, y) => (x.area.CompareTo(y.area)));
            districtHoleList = (from s in districtHoleListWithArea
                                select s.boundingBox).ToList();

            return districtHoleList;
        }


    }
}
